package cn.javaex.hgo.config.aop;

import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.apache.shiro.subject.Subject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import cn.javaex.hgo.action.system.dao.hgo_menu_info.IHgoMenuInfoDAO;
import cn.javaex.hgo.config.constant.HgoErrorMsg;
import cn.javaex.hgo.config.exception.HgoException;
import cn.javaex.hgo.util.HgoStringUtils;
import cn.javaex.hgo.util.HgoUtils;

/**
 * 统一日志管理
 * 
 * @author 陈霓清
 */
@Aspect
@Component
public class LogAspect {
	
	private Logger log = Logger.getLogger(this.getClass());
	
	@Autowired
	private IHgoMenuInfoDAO iHgoMenuInfoDAO;
	
	// 控制层包路径
	@Pointcut("execution(* cn.javaex.hgo.action.*.controller..*.*(..))")
	public void aopLog() {
		
	}
	
	/**
	 * 前置通知：在目标方法开始之前执行的通知
	 * @param joinPoint
	 * @throws HgoException
	 */
	@Before("aopLog()")
	public void doBefore(JoinPoint joinPoint) throws HgoException {
		ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attributes.getRequest();
		
		// 权限拦截
		// 1.0 获取当前应用项目名
		String domain = request.getSession().getServletContext().getContextPath();
		
		// 2.0 路径处理
		// 2.1 获取当前访问路径
		String url = request.getRequestURI();
		// 2.2 对路径进行处理
		// 2.2.1 去除路径中的项目名
		url = url.replaceFirst(domain, "");
		// 2.2.2 格式化url
		url = HgoStringUtils.formatUrl(url);
		
		// 3.0 查询所有权限标识
		Set<String> allPermCodeSet = iHgoMenuInfoDAO.listPermCode();
		if (allPermCodeSet!=null && allPermCodeSet.isEmpty()==false) {
			// 3.1 判断当前访问路径是否是权限标识
			if (allPermCodeSet.contains(url)) {
				// 3.2 判断当前用户是否有该权限
				Subject subject = HgoUtils.getSubject();
				if (!subject.isPermitted(url)) {
					throw new HgoException(HgoErrorMsg.ERROR_403);
				}
			}
		}
		
		String methodName = joinPoint.getSignature().getName();
		
		log.debug(url + ": " + methodName + "()==========>正常开始");
	}
	
	/**
	 * 返回通知：在目标方法正常结束时，才执行的通知
	 * @param joinPoint
	 */
	@AfterReturning("aopLog()")
	public void doAfterReturning(JoinPoint joinPoint) {
		ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attributes.getRequest();
		String url = request.getRequestURI();
		String methodName = joinPoint.getSignature().getName();
		log.debug(url + ": " + methodName + "()==========>正常终了");
	}
	
	/**
	 * 异常通知：在目标方法出现异常时才执行的通知
	 * @param joinPoint
	 * @param ex
	 */
	@AfterThrowing(pointcut="aopLog()", throwing="ex")
	public void afterThrowing(JoinPoint joinPoint, Exception ex) {
		ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attributes.getRequest();
		String url = request.getRequestURI();
		String methodName = joinPoint.getSignature().getName();
		log.error("请求路径：" + url);
		log.error("请求方法：" + methodName + "()==========>异常终了");
		log.error("异常原因：" + ex);
	}
}
